package com.xq.tmall.service;

import com.xq.tmall.agu.ferign.FetchBidStockSpider;
import com.xq.tmall.agu.ferign.FetchStockSpider;
import com.xq.tmall.dao.StockDao;
import com.xq.tmall.dao.StockFetchErrorDao;
import com.xq.tmall.entity.Stock;
import com.xq.tmall.entity.StockFetchError;
import com.xq.tmall.util.IpFerginUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author xiechuanxue
 * @date 2025/7/31 15:17
 * @description
 */
@Service
@Slf4j
public class StockFetchErrorService {

    // 批次管理
    private static final int BATCH_SIZE = 500;
    private static final int MAX_RETRIES = 3;
    private static final long RETRY_DELAY = 3000;

    @Resource
    private StockFetchErrorDao stockFetchErrorDao;

    @Resource
    private StockDao stockDao;

    @Autowired
    private IpFerginUtil ipFerginUtil;

    public int batchUpdate(List<String> stockCodeList,String fetchType){
        List<StockFetchError> stockFetchErrorList = new ArrayList<>();
        stockCodeList.stream().forEach(stockCode -> {
            StockFetchError stockFetchError = new StockFetchError();
            stockFetchError.setCode(stockCode);
            stockFetchError.setFetchType(fetchType);
            stockFetchError.setCreateTime(new Date());
            stockFetchError.setStatus("00");
            stockFetchErrorList.add(stockFetchError);
        });
        return stockFetchErrorDao.batchUpdate(stockFetchErrorList);
    }

    public String refreshStockFetch(String fetchType){
        List<StockFetchError> fetchErrorList = stockFetchErrorDao.findList(fetchType);
        if(CollectionUtils.isEmpty(fetchErrorList)){
            log.info("无需触发");
            return "";
        }
        List<String> stockCodeList = fetchErrorList.stream().map(StockFetchError::getCode).collect(Collectors.toList());
        ipFerginUtil.setRedisIp();
        if("01".equals(fetchType)){
            try {
                List<Stock> allResults = new ArrayList<>();
                // 分批处理股票代码
                for (int i = 0; i < stockCodeList.size(); i += BATCH_SIZE) {
                    int end = Math.min(i + BATCH_SIZE, stockCodeList.size());
                    List<String> batch = stockCodeList.subList(i, end);

                    log.info("正在处理批次: {}-{}/{}", i, end, stockCodeList.size());

                    List<Stock> batchResults = processStockBatch(batch.toArray(new String[0]));

                    if (!batchResults.isEmpty()) {
                        allResults.addAll(batchResults);
                    }

                    // 添加批次间隔，避免请求过于频繁
                    TimeUnit.MILLISECONDS.sleep(5000);
                }

                if (!allResults.isEmpty()) {
                    saveInVolumeBatches(allResults, 500);
                    log.info("任务完成，共保存 {} 条股票数据", allResults.size());
                    // 将数据任务数据修改成已完成
                    try {
                        List<String> codeList = allResults.stream().map(Stock::getCode).collect(Collectors.toList());
                        stockFetchErrorDao.updateByStockCode(codeList);
                    }catch (Exception e){
                        log.info("修改失败",e);
                    }
                } else {
                    log.warn("未获取到有效的股票数据");
                }
                return "success";
            }catch (Exception e){
                log.info("执行异常:",e);
                return "fail";
            }

        }else  if("02".equals(fetchType)){
            List<Stock>  allResults =  processMarket(stockCodeList);
            try {
                List<String> codeList = allResults.stream().map(Stock::getCode).collect(Collectors.toList());
                stockFetchErrorDao.updateByStockCode(codeList);
            }catch (Exception e){
                log.info("修改失败",e);
            }
            return "success";
        }
        return "fail";
    }

    private List<Stock> processMarket(List<String> stockCodeList) {
        log.info("开始处理市场");
        List<Stock> allResults = new ArrayList<>();
        try {

            log.info("共需处理 {} 只股票，分 {} 批处理",
                    stockCodeList.size(),
                    (int) Math.ceil((double) stockCodeList.size() / BATCH_SIZE));


            // 分批处理股票代码
            for (int i = 0; i < stockCodeList.size(); i += BATCH_SIZE) {
                int end = Math.min(i + BATCH_SIZE, stockCodeList.size());
                List<String> batch = stockCodeList.subList(i, end);

                log.info("正在处理批次: {}-{}/{}", i, end, stockCodeList.size());

                List<Stock> batchResults = processStockAllBatch(
                        batch.toArray(new String[0])
                );

                if (!batchResults.isEmpty()) {
                    allResults.addAll(batchResults);
                }

                // 添加批次间隔，避免请求过于频繁
                TimeUnit.MILLISECONDS.sleep(8000);
            }

            if (!allResults.isEmpty()) {
                saveInBatches(allResults, 500);
                log.info("任务完成，共保存 {} 条股票数据", allResults.size());
            } else {
                log.warn("未获取到有效的股票数据");
            }
        }catch (Exception e){
            log.info("抓取异常");
        }
        return allResults;
    }

    private List<Stock> processStockAllBatch(String[] codes) {
        int attempt = 0;
        while (attempt < MAX_RETRIES) {
            try {
                FetchStockSpider spider = new FetchStockSpider(codes);
                List<Stock> results = spider.fetchData();

                if (results != null && !results.isEmpty()) {
                    log.info("批次抓取成功，获取 {} 条数据", results.size());
                    return results;
                }
            } catch (Exception e) {
                log.warn("批次抓取失败 (尝试 {}/{}): {}",
                        attempt + 1, MAX_RETRIES, e.getMessage());
            }

            attempt++;
            try {
                TimeUnit.MILLISECONDS.sleep(RETRY_DELAY * attempt);
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
                break;
            }
        }
        log.error("批次抓取失败，已达到最大重试次数 {}", MAX_RETRIES);
        return Collections.emptyList();
    }

    private void saveInBatches(List<Stock> stocks, int batchSize) {
        int total = stocks.size();
        for (int i = 0; i < total; i += batchSize) {
            int end = Math.min(i + batchSize, total);
            List<Stock> batch = stocks.subList(i, end);

            try {
                stockDao.batchUpdate(batch);
                log.info("分批保存成功: {}-{}/{}", i, end, total);
            } catch (Exception e) {
                log.error("分批保存失败: {}-{}", i, end, e);
                // 单条保存作为降级方案
                saveOneByOne(batch);
            }
        }
    }

    private void saveOneByOne(List<Stock> stocks) {
        for (Stock stock : stocks) {
            try {
                stockDao.updateByPrimaryKeySelective(stock);
            } catch (Exception e) {
                log.error("保存股票失败: {}", stock.getCode(), e);
            }
        }
    }
    private List<Stock> processStockBatch(String[] codes) {
        int attempt = 0;
        while (attempt < MAX_RETRIES) {
            try {
                FetchBidStockSpider spider = new FetchBidStockSpider(codes);
                List<Stock> results = spider.fetchData();

                if (results != null && !results.isEmpty()) {
                    log.info("批次抓取成功，获取 {} 条数据", results.size());
                    return results;
                }
            } catch (Exception e) {
                log.warn("批次抓取失败 (尝试 {}/{}): {}",
                        attempt + 1, MAX_RETRIES, e.getMessage());
            }

            attempt++;
            try {
                TimeUnit.MILLISECONDS.sleep(RETRY_DELAY * attempt);
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
                break;
            }
        }
        log.error("批次抓取失败，已达到最大重试次数 {}", MAX_RETRIES);
        return Collections.emptyList();
    }

    private void saveInVolumeBatches(List<Stock> stocks, int batchSize) {
        int total = stocks.size();
        for (int i = 0; i < total; i += batchSize) {
            int end = Math.min(i + batchSize, total);
            List<Stock> batch = stocks.subList(i, end);
            try {
                stockDao.batchUpdateVolume(batch);
                log.info("分批保存成功: {}-{}/{}", i, end, total);
            } catch (Exception e) {
                log.error("分批保存失败: {}-{}", i, end, e);
            }
        }
    }
}
